package com.hongshu.idle.service.idle.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.GetResponse;
import com.alibaba.fastjson2.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hongshu.common.core.constant.NoteConstant;
import com.hongshu.common.core.enums.PayStatusEnum;
import com.hongshu.common.core.enums.PayTypeEnum;
import com.hongshu.common.core.enums.ResponseEnum;
import com.hongshu.common.core.exception.HongshuException;
import com.hongshu.idle.auth.AuthContextHolder;
import com.hongshu.idle.config.AliPayConfig;
import com.hongshu.idle.domain.entity.IdlePaymentOrder;
import com.hongshu.idle.domain.entity.IdlePaymentPay;
import com.hongshu.idle.domain.entity.IdleProduct;
import com.hongshu.idle.domain.vo.IdleProductVO;
import com.hongshu.idle.mapper.idle.IdlePaymentOrderMapper;
import com.hongshu.idle.mapper.idle.IdlePaymentPayMapper;
import com.hongshu.idle.mapper.idle.IdleProductMapper;
import com.hongshu.idle.service.idle.IIdlePaymentPayService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 商品
 *
 * @author: hongshu
 */
@Slf4j
@Service
public class IdlePaymentPayServiceImpl extends ServiceImpl<IdlePaymentPayMapper, IdlePaymentPay> implements IIdlePaymentPayService {

    @Autowired
    private IdlePaymentOrderMapper paymentOrderMapper;
    @Autowired
    private IdlePaymentPayMapper paymentPayMapper;
    @Autowired
    private IdleProductMapper productMapper;
    @Autowired
    private AliPayConfig aliPayConfig;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Value("${payment.timeout.minutes:15}")
    private int paymentTimeoutMinutes;


    /**
     * 创建订单
     *
     * @param paymentOrderId 订单信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createPaymentPay(String paymentOrderId) {
        // 1. 获取并验证订单
        IdlePaymentOrder order = this.validateOrder(paymentOrderId);
        // 2. 创建支付记录
        IdlePaymentPay pay = this.createPayRecord(order);
        // 3. 更新订单状态
        this.updateOrderStatus(order, pay);

        log.info("创建支付记录成功: orderId={}, payId={}, amount={}",
                order.getId(), pay.getId(), order.getPayPrice());

        return pay.getId();
    }

    private IdlePaymentOrder validateOrder(String paymentOrderId) {
        // 获取订单
        IdlePaymentOrder order = paymentOrderMapper.selectById(paymentOrderId);
        if (order == null) {
            throw new HongshuException(ResponseEnum.ERROR.getCode(), "订单不存在");
        }
        // 检查订单状态
        if (!PayStatusEnum.UN_PAY.getCode().equals(order.getOrderStatus())) {
            throw new HongshuException(ResponseEnum.ERROR.getCode(), "订单状态异常");
        }
        // 检查订单金额
        if (order.getPayPrice() <= 0) {
            throw new HongshuException(ResponseEnum.ERROR.getCode(), "订单金额必须大于0");
        }

        // 检查订单是否超时
        LocalDateTime orderCreateTime = order.getCreateTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        if (orderCreateTime.isBefore(LocalDateTime.now().minusMinutes(paymentTimeoutMinutes))) {
            log.warn("订单已超时: orderId={}, createTime={}", order.getId(), orderCreateTime);
            throw new HongshuException(ResponseEnum.ERROR.getCode(),
                    String.format("订单已超时（%d分钟），请重新下单", paymentTimeoutMinutes));
        }
        return order;
    }

    private IdlePaymentPay createPayRecord(IdlePaymentOrder order) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime expireTime = now.plusMinutes(paymentTimeoutMinutes);

        IdlePaymentPay pay = new IdlePaymentPay();
        pay.setOrderId(order.getId());
        pay.setUid(order.getUid());
        pay.setPaymentPrice(order.getPayPrice());
        pay.setPaymentType(PayTypeEnum.ALI_PAY.getCode());
        pay.setPaymentStatus(PayStatusEnum.UN_PAY.getCode());

        // 设置支付时间和超时时间
        pay.setPaymentTimeStart(now);
        pay.setPaymentTimeExpire(expireTime);

        // 设置创建和更新时间
        Date currentDate = new Date();
        pay.setCreateTime(currentDate);
        pay.setUpdateTime(currentDate);

        // 保存支付记录
        try {
            paymentPayMapper.insert(pay);
        } catch (Exception e) {
            log.error("创建支付记录失败: orderId={}", order.getId(), e);
            throw new HongshuException(ResponseEnum.ERROR.getCode(), "创建支付记录失败");
        }
        return pay;
    }

    private void updateOrderStatus(IdlePaymentOrder order, IdlePaymentPay pay) {
        order.setPaymentPayId(pay.getId());
        order.setPayType(pay.getPaymentType());
        order.setOrderStatus(PayStatusEnum.PEND_PAY.getCode());  // 更新为支付中状态
        order.setUpdateTime(new Date());

        try {
            paymentOrderMapper.updateById(order);
        } catch (Exception e) {
            log.error("更新订单状态失败: orderId={}, payId={}", order.getId(), pay.getId(), e);
            throw new HongshuException(ResponseEnum.ERROR.getCode(), "更新订单状态失败");
        }
    }


    @SneakyThrows
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> finishPay(String paymentPayId) {
        // 1. 数据验证
        IdlePaymentPay paymentPay = this.validateAndGetPaymentPay(paymentPayId);
        IdlePaymentOrder paymentOrder = this.validateAndGetPaymentOrder(paymentPay.getOrderId());

        // 2. 验证用户身份
//        String userId = WebUtils.getRequestHeader(UserConstant.USER_ID);
        String userId = AuthContextHolder.getUserId();
        if (!paymentOrder.getUid().equals(userId)) {
            throw new HongshuException(ResponseEnum.ERROR.getCode(), "无权操作此订单");
        }

        String lockKey = "payment:lock:" + paymentPayId;
        try {
            // 3. 使用分布式锁防止并发支付
            if (!redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS)) {
                throw new HongshuException(ResponseEnum.ERROR.getCode(), "订单正在处理中");
            }

            // 4. 检查订单状态
            if (PayStatusEnum.UN_PAY.getCode().equals(paymentPay.getPaymentStatus())
                    && PayStatusEnum.PEND_PAY.getCode().equals(paymentPay.getPaymentStatus())) {
                throw new HongshuException(ResponseEnum.ERROR.getCode(), "订单状态异常");
            }

            // 5. 检查订单是否过期
            Date createTime = paymentPay.getCreateTime();
            Date now = new Date();
            long diffInMillies = now.getTime() - createTime.getTime();
            long diffInMinutes = TimeUnit.MILLISECONDS.toMinutes(diffInMillies);

            if (diffInMinutes >= 15) {
                throw new HongshuException(ResponseEnum.ERROR.getCode(), "订单已过期，请重新下单");
            }

            // 5. 生成支付宝表单
            Map<String, Object> result = this.generateAlipayForm(paymentOrder);

            // 6. 更新订单状态为处理中
            paymentPay.setPaymentStatus(PayStatusEnum.PEND_PAY.getCode());
            paymentPay.setUpdateTime(new DateTime());
            paymentPayMapper.updateById(paymentPay);

            // 7. 输出HTML表单
            log.info("{}", result);
            return result;

        } catch (Exception e) {
            log.error("支付处理失败", e);
            throw new HongshuException(ResponseEnum.ERROR.getCode(), "支付处理失败");
        } finally {
            // 确保锁一定会被释放
            redisTemplate.delete(lockKey);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelPay(String paymentPayId) {
        // 1. 数据验证
        IdlePaymentPay paymentPay = this.validateAndGetPaymentPay(paymentPayId);
        IdlePaymentOrder paymentOrder = this.validateAndGetPaymentOrder(paymentPay.getOrderId());

        // 2. 验证用户身份
//        String userId = WebUtils.getRequestHeader(UserConstant.USER_ID);
        String userId = AuthContextHolder.getUserId();
        if (!paymentOrder.getUid().equals(userId)) {
            throw new HongshuException(ResponseEnum.ERROR.getCode(), "无权操作此订单");
        }

        // 3. 更新订单状态为未支付
        paymentPay.setPaymentStatus(PayStatusEnum.UN_PAY.getCode());
        paymentPay.setUpdateTime(new DateTime());
        paymentPayMapper.updateById(paymentPay);

        // 4.更新商品
        IdleProduct product = productMapper.selectById(paymentOrder.getProductId());
        product.setBuyUid("");
        product.setStatus(0);
        product.setUpdateTime(new Date());
        productMapper.updateById(product);
    }

    @Override
    public Object payStatus(String paymentPayId) {
        IdlePaymentPay paymentPay = this.validateAndGetPaymentPay(paymentPayId);
        return paymentPay.getPaymentStatus();
    }

    @Override
    public String handleAlipayNotify(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();

        try {
            // 1. 获取所有请求参数
            for (String name : requestParams.keySet()) {
                String[] values = requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
                }
                params.put(name, valueStr);
            }

            // 2. 验证交易状态
            String tradeStatus = params.get("trade_status");
            if (!"TRADE_SUCCESS".equals(tradeStatus)) {
                log.warn("收到非成功交易的支付宝回调: {}", tradeStatus);
                return "fail";
            }

            // 3. 验证签名
            String sign = params.get("sign");
            String content = AlipaySignature.getSignCheckContentV1(params);
            boolean checkSignature = AlipaySignature.rsa256CheckContent(content, sign,
                    aliPayConfig.getAlipayPublicKey(), "UTF-8");

            if (!checkSignature) {
                log.error("支付宝回调签名验证失败");
                return "fail";
            }

            // 4. 获取关键参数
            String outTradeNo = params.get("out_trade_no");
            String tradeNo = params.get("trade_no");
            String totalAmount = params.get("total_amount");
            String gmtPayment = params.get("gmt_payment");
            String sellerId = params.get("seller_id");

            // 5. 验证商家ID
            if (!aliPayConfig.getPid().equals(sellerId)) {
                log.error("收到非本商家的支付宝回调");
                return "fail";
            }

            // 6. 处理订单
            try {
                // 使用分布式锁防止重复处理
                String lockKey = "payment:notify:lock:" + outTradeNo;
                if (!redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS)) {
                    log.warn("订单正在处理中: {}", outTradeNo);
                    return "success";
                }

                try {
                    // 验证订单金额
                    IdlePaymentOrder order = paymentOrderMapper
                            .selectOne(new QueryWrapper<IdlePaymentOrder>().eq("order_number", outTradeNo));
                    if (order == null) {
                        log.error("未找到对应的订单: {}", outTradeNo);
                        return "fail";
                    }

                    // 验证订单金额（注意精度）
                    BigDecimal notifyAmount = new BigDecimal(totalAmount);
                    BigDecimal orderAmount = new BigDecimal(order.getPayPrice())
                            .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                    if (notifyAmount.compareTo(orderAmount) != 0) {
                        log.error("订单金额不匹配: {} != {}", notifyAmount, orderAmount);
                        return "fail";
                    }

                    // 更新订单状态
                    IdlePaymentPay pay = paymentPayMapper.selectById(order.getPaymentPayId());
                    pay.setPaymentStatus(PayStatusEnum.PAY.getCode());
                    pay.setUpdateTime(new Date());
                    paymentPayMapper.updateById(pay);
//                    boolean success = paymentOrderService.completePayment(order.getId(), tradeNo, gmtPayment);
//                    if (!success) {
//                        log.error("订单状态更新失败: {}", outTradeNo);
//                        return "fail";
//                    }

                    log.info("支付宝回调处理成功: 订单号={}, 交易号={}, 金额={}", outTradeNo, tradeNo, totalAmount);
                    return "success";

                } finally {
                    redisTemplate.delete(lockKey);
                }

            } catch (Exception e) {
                log.error("处理支付宝回调异常", e);
                return "fail";
            }

        } catch (Exception e) {
            log.error("支付宝回调处理异常", e);
            return "fail";
        }
    }

    /**
     * 更新支付状态
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrderStatus(String paymentOrderId) {
        IdlePaymentOrder order = paymentOrderMapper.selectById(paymentOrderId);
        order.setOrderStatus(PayStatusEnum.UN_PAY.getCode());
        order.setUpdateTime(new Date());
        paymentOrderMapper.updateById(order);

        IdleProduct product = productMapper.selectById(order.getProductId());
        product.setBuyUid("");
        product.setStatus(0);
        product.setUpdateTime(new Date());
        productMapper.updateById(product);
        // 更新ES数据
        this.updateEsProduct(product.getId(), 0);

        IdlePaymentPay pay = paymentPayMapper.selectById(order.getPaymentPayId());
        pay.setPaymentStatus(PayStatusEnum.UN_PAY.getCode());
        pay.setUpdateTime(new Date());
        paymentPayMapper.updateById(pay);
    }

    private void updateEsProduct(String productId, int status) {
        try {
            // Step 1: 获取现有的数据
            GetResponse<IdleProductVO> getResponse = elasticsearchClient.get(g -> g.index(NoteConstant.PRODUCT_INDEX).id(productId), IdleProductVO.class);
            // 检查是否获取到了数据
            if (getResponse.found()) {
                IdleProductVO productSearchVO = getResponse.source();
                // Step 2: 更新 status 字段
                productSearchVO.setStatus(status);
                // Step 3: 将更新后的数据保存回 Elasticsearch
                elasticsearchClient.update(u -> u.index(NoteConstant.PRODUCT_INDEX).id(productId).doc(productSearchVO), IdleProductVO.class);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 拆分验证逻辑
    private IdlePaymentPay validateAndGetPaymentPay(String paymentPayId) {
        IdlePaymentPay paymentPay = paymentPayMapper.selectById(paymentPayId);
        if (BeanUtil.isEmpty(paymentPay)) {
            throw new HongshuException(ResponseEnum.ERROR.getMsg());
        }
        return paymentPay;
    }

    private IdlePaymentOrder validateAndGetPaymentOrder(String orderId) {
        IdlePaymentOrder paymentOrder = paymentOrderMapper.selectById(orderId);
        if (BeanUtil.isEmpty(paymentOrder)) {
            throw new HongshuException(ResponseEnum.ERROR.getMsg());
        }
        return paymentOrder;
    }

    // 生成支付宝表单
    private Map<String, Object> generateAlipayForm(IdlePaymentOrder paymentOrder) throws AlipayApiException {
        // 创建支付宝配置
        AlipayConfig alipayConfig = new AlipayConfig();
        alipayConfig.setServerUrl(aliPayConfig.getGatewayUrl());
        alipayConfig.setAppId(aliPayConfig.getAppId());
        alipayConfig.setPrivateKey(aliPayConfig.getMerchantPrivateKey());
        alipayConfig.setFormat("json");
        alipayConfig.setCharset(aliPayConfig.getCharset());
        alipayConfig.setAlipayPublicKey(aliPayConfig.getAlipayPublicKey());
        alipayConfig.setSignType(aliPayConfig.getSignType());

        // 创建支付宝客户端
        AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);

        // 创建支付请求
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();

        // 构建业务参数
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", paymentOrder.getOrderNumber());
        BigDecimal amount = new BigDecimal(paymentOrder.getPayPrice())
                .setScale(2, RoundingMode.HALF_UP);
        bizContent.put("total_amount", amount.toString());
        bizContent.put("subject", String.format("订单支付-%s", paymentOrder.getOrderNumber()));
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
        bizContent.put("timeout_express", "15m");

        // 设置请求参数
        alipayRequest.setBizContent(bizContent.toString());
        alipayRequest.setReturnUrl(aliPayConfig.getReturnUrl());
        alipayRequest.setNotifyUrl(aliPayConfig.getNotifyUrl());

        // 执行请求
        AlipayTradePagePayResponse response = alipayClient.pageExecute(alipayRequest);
        if (response.isSuccess()) {
            return buildSuccessResult(paymentOrder.getOrderNumber(), response.getBody());
        } else {
            log.error("创建支付宝订单失败: {}, 错误码: {}, 错误信息: {}",
                    response.getMsg(), response.getSubCode(), response.getSubMsg());
            throw new HongshuException(ResponseEnum.ERROR.getCode(), "创建支付订单失败");
        }
    }

    // 提取构建返回结果的方法
    private Map<String, Object> buildSuccessResult(String orderNumber, String formHtml) {
        Map<String, Object> result = new HashMap<>();
        result.put("orderId", orderNumber);
        result.put("paymentFormHtml", formHtml);
        return result;
    }
}
